home *** CD-ROM | disk | FTP | other *** search
/ Programmers Heaven 2 / Programmers Heaven 2.iso / files / graphics / library / wgt51_r2.zip / WGT5 / SRC / WLINK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-03  |  17.3 KB  |  635 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <dos.h>
  4. #include <string.h>
  5. #include <bios.h>
  6. #include <conio.h>
  7. #include <mem.h>
  8. #include <dos.h>
  9. #include <i86.h>
  10.  
  11.  
  12. /*
  13. m
  14. ╔═════════════════════════════════════════════════════════════════╗
  15. ║             █▓▒░ WordUp Graphics Toolkit V5.0 ░▒▓█              ║
  16. ║    Source Code -- Public Domain (No Copyright)                  ║
  17. ╟─────────────────────────────────────────────────────────────────╢
  18. ║ Module:       wlink.c                                           ║
  19. ║ Contains:     wlink_answer, wlink_dial, wlink_flush_incoming,   ║
  20. ║               wlink_flush_outgoing, wlink_getuart,              ║
  21. ║               wlink_getvector, wlink_hangup_modem,              ║
  22. ║               wlink_initmodem, wlink_initport,                  ║
  23. ║               wlink_modemcommand, wlink_modemresponse,          ║
  24. ║               wlink_read_byte, wlink_shutdownport,              ║
  25. ║               wlink_write_buffer                                ║
  26. ║                                                                 ║
  27. ║ Last Revised: March 31, 1995                                    ║
  28. ║                                                                 ║
  29. ║ Most of this source code was adapted from the ser4 code         ║
  30. ║ which was originally released by Russell Gilbert.               ║
  31. ║ (gilbert@esd.dl.nec.com)                                        ║
  32. ║                                                                 ║
  33. ║ I have arranged the code in a flexible way so it is reusable    ║
  34. ║ with other applications.  Network support exists within ser4    ║
  35. ║ but since I do not have a network to test with, I left it out.  ║
  36. ║ If you would like to contribute code for this module, mail me   ║
  37. ║                                                                 ║
  38. ║ The packet reading/writing routines have been omitted.  You     ║
  39. ║ will have to design your own packet structure which suits your  ║
  40. ║ application.  You may want to look at the original ser4 source  ║
  41. ║ code for some ideas.                                            ║
  42. ╚═════════════════════════════════════════════════════════════════╝
  43. */
  44.  
  45. static struct {
  46.   char patch_id[8];
  47.   char fname[12];
  48.   float version;
  49. } patch_struct = {"WGTPATCH", "wlink", 1.0} ;
  50.  
  51. #define WLINK_NOVECTOR 0x67
  52. #define WLINK_8250_UART 0
  53. #define WLINK_16550_UART 1
  54.  
  55. #define TRANSMIT_HOLDING_REGISTER               0x00
  56. #define RECEIVE_BUFFER_REGISTER                 0x00
  57. #define INTERRUPT_ENABLE_REGISTER               0x01
  58. #define IER_RX_DATA_READY                       0x01
  59. #define IER_TX_HOLDING_REGISTER_EMPTY           0x02
  60. #define IER_LINE_STATUS                         0x04
  61. #define IER_MODEM_STATUS                        0x08
  62. #define INTERRUPT_ID_REGISTER                   0x02
  63. #define IIR_MODEM_STATUS_INTERRUPT              0x00
  64. #define IIR_TX_HOLDING_REGISTER_INTERRUPT       0x02
  65. #define IIR_RX_DATA_READY_INTERRUPT             0x04
  66. #define IIR_LINE_STATUS_INTERRUPT               0x06
  67. #define FIFO_CONTROL_REGISTER                   0x02
  68. #define FCR_FIFO_ENABLE                         0x01
  69. #define FCR_RCVR_FIFO_RESET                     0x02
  70. #define FCR_XMIT_FIFO_RESET                     0x04
  71. #define FCR_RCVR_TRIGGER_LSB                    0x40
  72. #define FCR_RCVR_TRIGGER_MSB                    0x80
  73. #define FCR_TRIGGER_01                          0x00
  74. #define FCR_TRIGGER_04                          0x40
  75. #define FCR_TRIGGER_08                          0x80
  76. #define FCR_TRIGGER_14                          0xc0
  77. #define LINE_CONTROL_REGISTER                   0x03
  78. #define LCR_WORD_LENGTH_MASK                    0x03
  79. #define LCR_WORD_LENGTH_SELECT_0                0x01
  80. #define LCR_WORD_LENGTH_SELECT_1                0x02
  81. #define LCR_STOP_BITS                           0x04
  82. #define LCR_PARITY_MASK                         0x38
  83. #define LCR_PARITY_ENABLE                       0x08
  84. #define LCR_EVEN_PARITY_SELECT                  0x10
  85. #define LCR_STICK_PARITY                        0x20
  86. #define LCR_SET_BREAK                           0x40
  87. #define LCR_DLAB                                0x80
  88. #define MODEM_CONTROL_REGISTER                  0x04
  89. #define MCR_DTR                                 0x01
  90. #define MCR_RTS                                 0x02
  91. #define MCR_OUT1                                0x04
  92. #define MCR_OUT2                                0x08
  93. #define MCR_LOOPBACK                            0x10
  94. #define LINE_STATUS_REGISTER                    0x05
  95. #define LSR_DATA_READY                          0x01
  96. #define LSR_OVERRUN_ERROR                       0x02
  97. #define LSR_PARITY_ERROR                        0x04
  98. #define LSR_FRAMING_ERROR                       0x08
  99. #define LSR_BREAK_DETECT                        0x10
  100. #define LSR_THRE                                0x20
  101. #define MODEM_STATUS_REGISTER                   0x06
  102. #define MSR_DELTA_CTS                           0x01
  103. #define MSR_DELTA_DSR                           0x02
  104. #define MSR_TERI                                0x04
  105. #define MSR_DELTA_CD                            0x08
  106. #define MSR_CTS                                 0x10
  107. #define MSR_DSR                                 0x20
  108. #define MSR_RI                                  0x40
  109. #define MSR_CD                                  0x80
  110. #define DIVISOR_LATCH_LOW                       0x00
  111. #define DIVISOR_LATCH_HIGH                      0x01
  112. #define CLOCK_FREQUENCY                         1843200         /* 1.8432 Mhz */
  113.  
  114. short uart_type;
  115.  
  116. #define BUFFERSIZE      4096
  117. /* BUFFERSIZE must be a power of 2 */
  118.  
  119. typedef struct
  120. {
  121.  short head, tail;                // bytes are put on head and pulled from tail
  122.  short size;
  123.  unsigned char data[BUFFERSIZE];
  124. } transferbuffer;
  125.  
  126. union REGS regs;
  127. struct SREGS sregs;
  128.  
  129. void (__interrupt __far *oldirqvect) (void);
  130. short irqintnum;
  131.  
  132. transferbuffer buffer_in, buffer_out;
  133.  
  134. short line_status = -1;
  135.  
  136. void __interrupt isr8 (void);
  137. void __interrupt isr16 (void);
  138.  
  139. /* Modem variables */
  140. short pulsedial = 0;
  141. short usemodem = 0;
  142.  
  143. struct {
  144.   char modem_init [257];
  145.   char modem_hangup [257];
  146.   unsigned long baud_rate;
  147.   short com_port;
  148.   short irq_num;
  149.   short uart;
  150.   short uarttype;
  151.   short vector;
  152.  } link_info;
  153.  
  154.  
  155.  
  156.  
  157. void *FIRSTMEG (void *x)
  158. {
  159.  return (void *)((unsigned short)(x) + (((unsigned long)(x)>>12) & 0xffff0));
  160. }
  161.  
  162.  
  163. /* Empties the incoming buffer */
  164. void wlink_flush_incoming (void)
  165. {
  166.  buffer_in.tail = buffer_in.head;
  167.  buffer_in.size = 0;
  168. }
  169.  
  170. /* Empties the outgoing buffer */
  171. void wlink_flush_outgoing (void)
  172. {
  173.  buffer_out.tail = buffer_out.head;
  174.  buffer_out.size = 0;
  175. }
  176.  
  177.  
  178. /* Finds out what kind of UART is installed. */
  179. void wlink_getuart (void)
  180. {
  181. char *system_data;
  182. static short ISA_uarts[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
  183. static short ISA_IRQs[] = {4, 3, 4, 3};
  184. static short MCA_uarts[] = {0x03f8, 0x02f8, 0x3220, 0x3228};
  185. static short MCA_IRQs[] = {4, 3, 3, 3};
  186.  
  187.  segread ( &sregs);
  188.  
  189.  regs.h.ah = 0xc0;
  190.  int386x (0x15, ®s, ®s, &sregs);
  191.  if (regs.w.cflag)
  192.   {
  193.    if (link_info.irq_num == -1)
  194.        link_info.irq_num = ISA_IRQs[link_info.com_port - 1];
  195.    if (link_info.uart == -1)
  196.        link_info.uart = ISA_uarts[link_info.com_port - 1];
  197.    return;
  198.   }
  199.  
  200.  system_data = (char *) (((long) sregs.es << 16) + regs.w.bx);
  201.  if (system_data[5] & 0x02)
  202.   {
  203.    if (link_info.irq_num == -1)
  204.        link_info.irq_num = MCA_IRQs[link_info.com_port-1];
  205.    if (link_info.uart == -1)
  206.        link_info.uart = MCA_uarts[link_info.com_port-1];
  207.   }
  208.  else
  209.   {
  210.    if (link_info.irq_num == -1)
  211.        link_info.irq_num = ISA_IRQs[link_info.com_port-1];
  212.    if (link_info.uart == -1)
  213.        link_info.uart = ISA_uarts[link_info.com_port-1];
  214.   }
  215. }
  216.  
  217.  
  218. /* Finds out what interrupt vector is being used. */
  219. void wlink_getvector (void)
  220. {
  221. unsigned char *vectorptr;
  222. unsigned char *vectorptr2;
  223. unsigned char readbyte;
  224.  
  225.  /* Get an interrupt vector if not already set */
  226.  if (link_info.vector == -1)
  227.   {
  228.    for (link_info.vector = 0x60; link_info.vector <= 0x66; link_info.vector++)
  229.     {
  230.      vectorptr = (void *)(link_info.vector * 4);
  231.      vectorptr = (unsigned char *)FIRSTMEG(vectorptr);
  232.      vectorptr2 = (unsigned char *)FIRSTMEG(*vectorptr);
  233.      readbyte = *vectorptr2;
  234.  
  235.      if ((!(vectorptr2)) || (readbyte == 0xcf))
  236.      break;
  237.     }
  238.   }
  239. }
  240.  
  241. /* 8250 Interrupt.  One byte at a time. */
  242. void __interrupt isr8 (void)
  243. {
  244. short c;
  245.  
  246.  _disable ();
  247.  
  248.  
  249.  while (1)
  250.   {
  251.    switch (inp (link_info.uart + INTERRUPT_ID_REGISTER) & 7)
  252.     {
  253.      /* receive exactly one byte */
  254.      case IIR_RX_DATA_READY_INTERRUPT :
  255.     c = inp (link_info.uart + RECEIVE_BUFFER_REGISTER);
  256.     buffer_in.data[buffer_in.head++] = c;
  257.     buffer_in.size++;
  258.     if (buffer_in.head >= BUFFERSIZE)
  259.     buffer_in.head = 0;      /* wrap around */
  260.      break;
  261.  
  262.      /* transmit exactly one byte */
  263.      case IIR_TX_HOLDING_REGISTER_INTERRUPT :
  264.     if (buffer_out.size != 0)
  265.      {
  266.       c = buffer_out.data[buffer_out.tail++];
  267.       buffer_out.size--;
  268.       if (buffer_out.tail >= BUFFERSIZE)
  269.           buffer_out.tail = 0;      /* wrap around */
  270.       outp (link_info.uart + TRANSMIT_HOLDING_REGISTER, c);
  271.      }
  272.      break;
  273.  
  274.      /* line status */
  275.      case IIR_LINE_STATUS_INTERRUPT :
  276.     line_status = inp (link_info.uart + LINE_STATUS_REGISTER);
  277.      break;
  278.  
  279.      /* done */
  280.      default :
  281.      outp (0x20, 0x20);
  282.      _enable();
  283.      return;
  284.     }
  285.   }
  286. }
  287.  
  288.  
  289. /* 16550 interrupt. */
  290. void __interrupt isr16 (void)
  291. {
  292. short c;
  293. short count;
  294.  
  295.  _disable ();
  296.  
  297.  while (1)
  298.   {
  299.    switch (inp (link_info.uart + INTERRUPT_ID_REGISTER) & 7)
  300.     {
  301.      /* receive */
  302.      case IIR_RX_DATA_READY_INTERRUPT:
  303.     do
  304.      {
  305.       c = inp (link_info.uart + RECEIVE_BUFFER_REGISTER);
  306.       buffer_in.data[buffer_in.head++] = c;
  307.       buffer_in.size++;
  308.       if (buffer_in.head >= BUFFERSIZE)
  309.          buffer_in.head = 0;      // wrap around
  310.      } while (inp (link_info.uart + LINE_STATUS_REGISTER) & LSR_DATA_READY );
  311.      break;
  312.  
  313.      /* transmit */
  314.      case IIR_TX_HOLDING_REGISTER_INTERRUPT :
  315.     if (buffer_out.size != 0)
  316.      {
  317.       count = 16;
  318.       do
  319.        {
  320.         c = buffer_out.data[buffer_out.tail++];
  321.         buffer_out.size--;
  322.         if (buffer_out.tail >= BUFFERSIZE)
  323.         buffer_out.tail = 0;      /* wrap around */
  324.  
  325.         outp (link_info.uart + TRANSMIT_HOLDING_REGISTER, c);
  326.        } while (--count && buffer_out.size != 0);
  327.      }
  328.     break;
  329.  
  330.      /* line status */
  331.      case IIR_LINE_STATUS_INTERRUPT :
  332.     line_status = inp (link_info.uart + LINE_STATUS_REGISTER);
  333.      break;
  334.  
  335.      /* done */
  336.      default :
  337.     outp (0x20, 0x20);
  338.     _enable();
  339.     return;
  340.     }
  341.   }
  342. }
  343.  
  344.  
  345.  
  346. /* Returns a byte out of the incoming buffer. Returns -1 if the buffer
  347.    is empty. */
  348. short wlink_read_byte (void)
  349. {
  350. short c;
  351.  
  352.  if (buffer_in.size == 0)
  353.      return -1;
  354.  
  355.  c = buffer_in.data[buffer_in.tail++];
  356.  buffer_in.size--;
  357.  
  358.  if (buffer_in.tail >= BUFFERSIZE)
  359.      buffer_in.tail = 0;      /* wrap around */
  360.  
  361.  return c;
  362. }
  363.  
  364.  
  365. /* Writes one byte into the outgoing buffer. */
  366. void write_byte (unsigned char c)
  367. {
  368.  buffer_out.data[buffer_out.head++] = c;
  369.  buffer_out.size++;
  370.  
  371.  if (buffer_out.head >= BUFFERSIZE)
  372.      buffer_out.head = 0;     /* wrap around */
  373. }
  374.  
  375.  
  376. /* Writes a string of bytes into the outgoing buffer. */
  377. void wlink_write_bytes (unsigned char *buf, int count)
  378. {
  379.  if (buffer_out.head + count >= BUFFERSIZE)
  380.   /* String would wrap around the buffer */
  381.   {
  382.    while (count--)
  383.      write_byte (*buf++);
  384.   }
  385.  else
  386.   {
  387.    memcpy(buffer_out.data + buffer_out.head, buf, count);
  388.    /* Write all at once */
  389.    buffer_out.head += count;
  390.    buffer_out.size += count;
  391.   }
  392. }
  393.  
  394.  
  395. /* Start the write interrupts by sending the first char. */
  396. void jump_start (void)
  397. {
  398. short c;
  399.  
  400.  if (buffer_out.size != 0)
  401.   {
  402.    c = buffer_out.data [buffer_out.tail++];
  403.    buffer_out.size--;
  404.    if (buffer_out.tail >= BUFFERSIZE)
  405.        buffer_out.tail = 0;      /* wrap around */
  406.    outp (link_info.uart, c);
  407.   }
  408. }
  409.  
  410.  
  411. /* Write a packet of information. */
  412. void wlink_write_buffer (unsigned char *buffer, unsigned int count)
  413. {
  414.  /* if this would overrun the buffer, throw everything else out */
  415.  if (buffer_out.size + count > BUFFERSIZE)
  416.   {
  417.    buffer_out.tail = buffer_out.head;
  418.    buffer_out.size = 0;
  419.   }
  420.  
  421.  wlink_write_bytes (buffer, count);
  422.  
  423.  if (inp (link_info.uart + LINE_STATUS_REGISTER) & 0x40)
  424.      jump_start ();
  425. }
  426.  
  427.  
  428. /* Initialize the communications port. */
  429. void wlink_initport (void)
  430. {
  431. short mcr;
  432. short temp;
  433. unsigned long divisor;
  434.  
  435.  if ((divisor = link_info.baud_rate) == 14400)
  436.    divisor = 19200;
  437.  
  438.  divisor = CLOCK_FREQUENCY / (16 * divisor);      /* Calc. divisor */
  439.  outp (link_info.uart + LINE_CONTROL_REGISTER, LCR_DLAB); /* Enable divisor */
  440.  outp (link_info.uart + DIVISOR_LATCH_HIGH, 0);           /* Set divisor */
  441.  outp (link_info.uart + DIVISOR_LATCH_LOW, (unsigned char) divisor);
  442.  outp (link_info.uart + LINE_CONTROL_REGISTER, 3);        /* Set 8,n,1 */
  443.      
  444.  /* check for a 16550 */
  445.  outp (link_info.uart + FIFO_CONTROL_REGISTER, FCR_FIFO_ENABLE + FCR_TRIGGER_04);
  446.  temp = inp (link_info.uart + INTERRUPT_ID_REGISTER);
  447.  if ( ( temp & 0xf8 ) == 0xc0 )
  448.    uart_type = WLINK_16550_UART;
  449.  else
  450.   {
  451.    uart_type = WLINK_8250_UART;
  452.    outp (link_info.uart + FIFO_CONTROL_REGISTER, 0);
  453.   }
  454.  
  455.  link_info.uarttype = uart_type;
  456.  /* prepare for interrupts */
  457.  outp (link_info.uart + INTERRUPT_ENABLE_REGISTER, 0);  /* Turn off interrupts */
  458.  mcr = inp (link_info.uart + MODEM_CONTROL_REGISTER);   /* Get modem status */
  459.  mcr |= MCR_OUT2;                               /* Set GPO 2 */
  460.  mcr &= ~MCR_LOOPBACK;                          /* Turn off loopback test */
  461.  mcr |= MCR_DTR;                                /* Set DTR */   mcr |= MCR_RTS;                                                                                 /* Set RTS */
  462.  outp (link_info.uart + MODEM_CONTROL_REGISTER, mcr);   /* Set modem status */
  463.  
  464.  inp (link_info.uart);                                  /* Clear Rx interrupts */
  465.  inp (link_info.uart + INTERRUPT_ID_REGISTER);          /* Clear Tx interrupts */
  466.  
  467.  /* hook the irq vector */
  468.  irqintnum = link_info.irq_num + 8;
  469.  
  470.  oldirqvect = _dos_getvect (irqintnum);
  471.  if (uart_type == WLINK_8250_UART)                      /* Use different interrupt routines */
  472.   _dos_setvect (irqintnum, isr8);
  473.  else
  474.   _dos_setvect (irqintnum, isr16);
  475.  
  476.  outp (0x20 + 1, inp( 0x20 + 1 ) & ~(1<<link_info.irq_num));
  477.  
  478.  _disable();
  479.  
  480.  /* enable RX and TX interrupts at the uart
  481.     also enable Line Status interrupts to watch for errors. */
  482.  
  483.  outp (link_info.uart + INTERRUPT_ENABLE_REGISTER,
  484.      IER_RX_DATA_READY + IER_TX_HOLDING_REGISTER_EMPTY + IER_LINE_STATUS);
  485.  
  486.  /* enable interrupts through the interrupt controller */
  487.  
  488.  outp (0x20, 0xc2);
  489.  _enable ();
  490. }
  491.  
  492.  
  493. /* Close the communications port. */
  494. void wlink_shutdownport (void)
  495. {
  496.  outp (link_info.uart + INTERRUPT_ENABLE_REGISTER, 0);  /* Turn off interrupts */
  497.  outp (link_info.uart + MODEM_CONTROL_REGISTER, 0);     /* Clear modem status */
  498.  outp (link_info.uart + FIFO_CONTROL_REGISTER, 0);      /* Clear fifo status */
  499.  
  500.  outp (0x20 + 1, inp (0x20 + 1) | (1<<link_info.irq_num));
  501.  
  502.  _dos_setvect (irqintnum,oldirqvect);                   /* Return to original interrupt */
  503. }
  504.  
  505.  
  506. /* Hangs up the modem */
  507. void wlink_hangup_modem (void)
  508. {
  509.  outp (link_info.uart + MODEM_CONTROL_REGISTER,
  510.      inp( link_info.uart + MODEM_CONTROL_REGISTER ) & ~MCR_DTR);
  511.  delay (1250);
  512.  outp (link_info.uart + MODEM_CONTROL_REGISTER,
  513.      inp( link_info.uart + MODEM_CONTROL_REGISTER ) | MCR_DTR);
  514.  wlink_modemcommand("+++");
  515.  delay (1250);
  516.  if (link_info.modem_hangup [0] != '\0')
  517.      wlink_modemcommand (link_info.modem_hangup);
  518.  else
  519.   {
  520.    wlink_modemcommand ("ATH0");
  521.   }
  522.  delay (1250);
  523.  while (wlink_read_byte () != -1);
  524. }
  525.  
  526.  
  527. /* Writes a command to the modem */
  528. void wlink_modemcommand (char *str)
  529. {
  530.  short i;
  531. char *ptr;
  532.  
  533.  ptr = str;
  534.  for (i = 0; i < strlen (str); i++)
  535.   {
  536.    wlink_write_buffer (ptr++, 1);
  537.    delay (20);
  538.   }
  539.  wlink_write_buffer ("\r",1);
  540. }
  541.  
  542.  
  543. /* Write the modem string and look for an OK message */
  544. int wlink_initmodem (void)
  545. {
  546.  if (link_info.modem_init [0] != '\0')
  547.   {
  548.    wlink_modemcommand (link_info.modem_init);
  549.    return (wlink_modemresponse ("OK"));
  550.   }
  551. return 1;
  552. }
  553.  
  554.  
  555.  
  556.  
  557. /* ------------------------------ MODEM Routines ------------------------- */
  558.  
  559.  
  560. int wlink_modemresponse (char *resp)
  561. {
  562. short c;
  563. short respptr;
  564. char response[80];
  565.  
  566.  do
  567.  {
  568.   respptr = 0;
  569.  
  570.   do
  571.    {
  572.     while ( _bios_keybrd(1) )
  573.      {
  574.       if ( (_bios_keybrd (0) & 0xff) == 27)
  575.        {
  576.     //printf ("\nModem response aborted.\n");
  577.     //wlink_hangup_modem ();
  578.     return 0;
  579.        }
  580.      }
  581.     c = wlink_read_byte ();
  582.     if (c == -1)
  583.     continue;
  584.     if (c == '\n' || respptr == 79)
  585.      {
  586.       response[respptr] = 0;
  587.       //printf ("%s\n", response);
  588.       break;
  589.      }
  590.     if (c >= ' ')
  591.      {
  592.       response[respptr] = c;
  593.       respptr++;
  594.      }
  595.    } while (1);
  596.  
  597.  } while (strncmp (response, resp, strlen (resp)));
  598. return 1;
  599. }
  600.  
  601.  
  602. int wlink_dial (char *dialstring)
  603. {
  604. char cmd[80];
  605.  
  606.  usemodem = 1;
  607.  
  608.  wlink_initmodem ();
  609.  
  610.  if (pulsedial)
  611.      sprintf (cmd,"ATDP%s", dialstring);
  612.  else
  613.      sprintf (cmd,"ATDT%s", dialstring);
  614.  
  615.  wlink_modemcommand (cmd);
  616.  return wlink_modemresponse ("CONNECT");
  617. }  
  618.  
  619.  
  620. int wlink_answer (void)
  621. {
  622.  usemodem = 1;
  623.  wlink_initmodem ();
  624.  
  625.  if (! wlink_modemresponse ("RING"))
  626.      return 0;
  627.  wlink_modemcommand ("ATA");
  628.  return wlink_modemresponse ("CONNECT");
  629. }
  630.  
  631.  
  632.  
  633.  
  634.  
  635.